#include "album_picture.h"
#include "file_utils.h"
#include "elog.h"
#include "elog_file.h"
#include "album_common.h"
#include "img_utils.h"

#include <stdlib.h>

#include <string>
#include <filesystem>

namespace fs = std::filesystem;

static sqlite3* m_db = nullptr;
static std::string picture_table_name = "pictureInfo";
static std::string picture_folder_path = album_path + photograph_path;


AlbumPicture::AlbumPicture() {

}

AlbumPicture::~AlbumPicture() {

}

int AlbumPicture::createPictureInfoTable(sqlite3* db) {
    char* errMsg = 0;
    int rc;

    m_db = db;
    // 创建pictureInfo表（如果还未创建）
    const char* createTableSQL = R"(
        CREATE TABLE IF NOT EXISTS pictureInfo (
            id INTEGER PRIMARY KEY,
            file_path TEXT UNIQUE,
            modification_time INTEGER,
            file_size INTEGER,
            thumbnail_path TEXT,
            width INTEGER,
            height INTEGER,
            media_type INTEGER
        );
    )";

    rc = sqlite3_exec(m_db, createTableSQL, NULL, 0, &errMsg);
    if (rc != SQLITE_OK) {
        log_e("cannot create table: %s", errMsg);
        sqlite3_free(errMsg);
    } else {
        log_i("create table successfully");
    }

    return 0;
}

int AlbumPicture::insertPictureInfo(const PictureInfo& picture_info) {
    log_i("insertPictureInfo file_path = %s", picture_info.common_info.file_path.c_str());
    if (!m_db) {
        log_e("The database connection is not initialized");
        return -1;
    }

    std::string insertDataSQL = "INSERT INTO " + picture_table_name + " (file_path, modification_time, file_size, thumbnail_path, width, height, media_type) VALUES (?, ?, ?, ?, ?, ?, ?);";

    sqlite3_stmt* stmt;
    int rc = sqlite3_prepare_v2(m_db, insertDataSQL.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return -1;
    }

    sqlite3_bind_text(stmt, 1, picture_info.common_info.file_path.c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_int64(stmt, 2, picture_info.common_info.modification_time);
    sqlite3_bind_int64(stmt, 3, picture_info.common_info.file_size);
    sqlite3_bind_text(stmt, 4, picture_info.common_info.thumbnail_path.c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_int(stmt, 5, picture_info.common_info.width);
    sqlite3_bind_int(stmt, 6, picture_info.common_info.height);
    sqlite3_bind_int(stmt, 7, picture_info.common_info.media_type);

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        log_e("can not insert :%s", sqlite3_errmsg(m_db));
        sqlite3_finalize(stmt);
        return -1;
    }

    sqlite3_finalize(stmt);

    return 0;
}

int AlbumPicture::getCount() {
    int count = 0;

    if (!m_db) {
        log_e("The database connection is not initialized");
        return count;
    }

    std::string sql = "SELECT COUNT(*) FROM " + picture_table_name + ";";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return count;
    }

    if (sqlite3_step(stmt) == SQLITE_ROW) {
        count = sqlite3_column_int(stmt, 0);
    }

    sqlite3_finalize(stmt);

    return count;
}


std::vector<PictureInfo> AlbumPicture::queryPictureInfoByTime() {
    std::vector<PictureInfo> result;

    if (!m_db) {
        log_e("The database connection is not initialized");
        return result;
    }

    std::string sql = "SELECT * FROM " + picture_table_name + " ORDER BY modification_time DESC;";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return result;
    }

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        PictureInfo info;
        info.common_info.file_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
        info.common_info.modification_time = sqlite3_column_int64(stmt, 2);
        info.common_info.file_size = sqlite3_column_int64(stmt, 3);
        info.common_info.thumbnail_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
        info.common_info.width = sqlite3_column_int(stmt, 5);
        info.common_info.height = sqlite3_column_int(stmt, 6);
        info.common_info.media_type = sqlite3_column_int(stmt, 7);
        result.push_back(info);
    }

    sqlite3_finalize(stmt);

    return result;
}
    
std::vector<PictureInfo> AlbumPicture::queryAllPictureInfo() {
    std::vector<PictureInfo> result;

    if (!m_db) {
        log_e("The database connection is not initialized");
        return result;
    }

    std::string sql = "SELECT * FROM " + picture_table_name + ";";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return result;
    }

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        PictureInfo info;
        info.common_info.file_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
        info.common_info.modification_time = sqlite3_column_int64(stmt, 2);
        info.common_info.file_size = sqlite3_column_int64(stmt, 3);
        info.common_info.thumbnail_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
        info.common_info.width = sqlite3_column_int(stmt, 5);
        info.common_info.height = sqlite3_column_int(stmt, 6);
        info.common_info.media_type = sqlite3_column_int(stmt, 7);
        result.push_back(info);
    }

    sqlite3_finalize(stmt);

    return result;
}

std::vector<PictureInfo> AlbumPicture::queryPictureInfoByFilepath(const std::string& file_path) {
    std::vector<PictureInfo> result;

    if (!m_db) {
        log_e("The database connection is not initialized");
        return result;
    }

    std::string sql = "SELECT * FROM " + picture_table_name + " WHERE file_path = ?";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return result;
    }

    sqlite3_bind_text(stmt, 1, file_path.c_str(), -1, SQLITE_STATIC);

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        PictureInfo info;
        info.common_info.file_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
        info.common_info.modification_time = sqlite3_column_int64(stmt, 2);
        info.common_info.file_size = sqlite3_column_int64(stmt, 3);
        info.common_info.thumbnail_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
        info.common_info.width = sqlite3_column_int(stmt, 5);
        info.common_info.height = sqlite3_column_int(stmt, 6);
        info.common_info.media_type = sqlite3_column_int(stmt, 7);
        result.push_back(info);
    }

    sqlite3_finalize(stmt);

    return result;
}

std::vector<PictureInfo> AlbumPicture::queryPictureInfoByTime(int page_index, int page_size) {
    std::vector<PictureInfo> result;

    if (!m_db) {
        log_e("The database connection is not initialized");
        return result;
    }

    std::string sql = "SELECT * FROM " + picture_table_name + " ORDER BY modification_time DESC LIMIT ? OFFSET ?;";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return result;
    }

    int offset = page_index * page_size;            // page_index从0开始
    sqlite3_bind_int(stmt, 1, page_size);
    sqlite3_bind_int(stmt, 2, offset);

    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        PictureInfo info;
        info.common_info.file_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
        info.common_info.modification_time = sqlite3_column_int64(stmt, 2);
        info.common_info.file_size = sqlite3_column_int64(stmt, 3);
        info.common_info.thumbnail_path = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
        info.common_info.width = sqlite3_column_int(stmt, 5);
        info.common_info.height = sqlite3_column_int(stmt, 6);
        info.common_info.media_type = sqlite3_column_int(stmt, 7);
        result.push_back(info);
    }

    sqlite3_finalize(stmt);

    return result;
}

bool AlbumPicture::updatePictureInfo(const std::string& file_path, const std::string& new_file_path) {
    if (!m_db) {
        log_e("The database connection is not initialized");
        return false;
    }

    std::string sql = "UPDATE " + picture_table_name + " SET file_path = ? WHERE file_path = ?;";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return false;
    }

    sqlite3_bind_text(stmt, 1, new_file_path.c_str(), -1, SQLITE_STATIC);
    sqlite3_bind_text(stmt, 2, file_path.c_str(), -1, SQLITE_STATIC);

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        log_e("can not update: %s", sqlite3_errmsg(m_db));
        sqlite3_finalize(stmt);
        return false;
    }

    sqlite3_finalize(stmt);

    return true;
}

bool AlbumPicture::deletePictureInfo(const std::string& file_path) {
    log_i("deletePictureInfo file_path = %s", file_path.c_str());

    if (!m_db) {
        log_e("The database connection is not initialized");
        return false;
    }

    std::string sql = "DELETE FROM " + picture_table_name + " WHERE file_path = ?;";
    sqlite3_stmt* stmt;

    int rc = sqlite3_prepare_v2(m_db, sql.c_str(), -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        log_e("can not prepare sql: %s", sqlite3_errmsg(m_db));
        return false;
    }

    sqlite3_bind_text(stmt, 1, file_path.c_str(), -1, SQLITE_STATIC);

    rc = sqlite3_step(stmt);
    if (rc != SQLITE_DONE) {
        log_e("can not delete: %s", sqlite3_errmsg(m_db));
        sqlite3_finalize(stmt);
        return false;
    }

    sqlite3_finalize(stmt);
    
    return true;
}
    
void AlbumPicture::printPictureInfo(const PictureInfo& picture_info) {
    log_i("picture_info file_path = %s", picture_info.common_info.file_path.c_str());
    log_i("picture_info modification_time = %ld", picture_info.common_info.modification_time);
    log_i("picture_info file_size = %d", picture_info.common_info.file_size);
}


bool AlbumPicture::deletePicture(const std::string& file_path) {
    if (file_path != "" && isPathContains(file_path, picture_folder_path) && file_path.size() > picture_folder_path.size()) {
        std::string thumbnail_path = picture_folder_path + photo_thumbnail_path + getFileName(file_path);
        if (deletePictureInfo(file_path) && deleteFile(file_path) && deleteFile(thumbnail_path)) {
            return true;
        } else {
            return false;
        }
    }

    return false;
}

bool AlbumPicture::renamePicture(const std::string& file_path, const std::string& new_filename) {
    if (file_path != "" && isPathContains(file_path, picture_folder_path) && file_path.size() > picture_folder_path.size()) {
        std::string extension = getFileExtension(file_path);
        std::string new_file_path = picture_folder_path + new_filename + extension;
        if (renameFile(file_path, new_file_path)) {
            updatePictureInfo(file_path, new_file_path);
            return true;
        } else {
            return false;
        }
    }

    return false;
}

// 拍完照片后调用
bool AlbumPicture::updatePicture(const std::string& file_path) {
    if (file_path != "" && isPathContains(file_path, picture_folder_path) && file_path.size() > picture_folder_path.size()) {
        PictureInfo info;
        info.common_info.file_path = file_path;
        info.common_info.modification_time = getFileModifiedTime(file_path);
        info.common_info.file_size = getFileSizeInt(file_path);
        info.common_info.media_type = MEDIA_PICTURE;
        info.common_info.width = 3840;
        info.common_info.height = 2160;

        std::string thumbnail_path = picture_folder_path + photo_thumbnail_path + getFileName(file_path);
        log_i("updatePicture file_path = %s, thumbnail_path = %s", file_path.c_str(), thumbnail_path.c_str());
        if (fs::exists(file_path)) {
            imageDownsample(file_path, thumbnail_path, album_thumbnail_width, album_thumbnail_height);
        }

        if (fs::exists(thumbnail_path)) {
            info.common_info.thumbnail_path = thumbnail_path;
        }

        insertPictureInfo(info);
        fileSync();
        
        return true;
    }

    return false;
}

